Skip to content

Comments

Mesh Pipelines#982

Open
GDBobby wants to merge 1 commit intoDevsh-Graphics-Programming:masterfrom
GDBobby:master
Open

Mesh Pipelines#982
GDBobby wants to merge 1 commit intoDevsh-Graphics-Programming:masterfrom
GDBobby:master

Conversation

@GDBobby
Copy link

@GDBobby GDBobby commented Jan 6, 2026

Mesh Pipelines

Description of changes that aren't implicit.

  1. Reordered every mention of Graphics, Compute, Mesh, and Raytracing pipelines to follow that order. For example, in line 331 of IGPUCommandBuffer, Compute was moved below Graphics, and mesh was put below compute, which is above raytracing.
  2. In ILogicalDevice, I abstracted the commonalities between Graphics and Mesh pipeline creation. The end result for Graphics doesn't change at all.
  3. I'll probably need help with the features and limits. I included the bare minimum.
  4. As requested, GetBoundGraphicsPipeline now returns IGPUPipelineBase, and both mesh and graphics bind as the RasterizationPipeline.

Testing

https://github.com/GDBobby/Nabla-Examples-and-Tests/tree/master/MeshShader

@devshgraphicsprogrammingjenkins
Copy link
Contributor

[CI]: Can one of the admins verify this patch?

@devshgraphicsprogramming
Copy link
Member

devshgraphicsprogramming commented Feb 23, 2026

@GDBobby there's a huge PR dropping this week #1000

After this there will be an example in CI mode that loads dozens of models and screenshots them

Let me know if thats something that will help you

Either way the branch will need to get master merged into it so the CI can run.

Comment on lines -588 to +596
const IGPUGraphicsPipeline* getBoundGraphicsPipeline() const { return m_boundGraphicsPipeline; }
const IGPUPipelineBase* getBoundGraphicsPipeline() const { return m_boundRasterizationPipeline; }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have a RasterizationPipelineBase, cause PipelineBase is also inherited from by RT and compute

Comment on lines +447 to +450
bool drawMeshTasks(const uint32_t groupCountX, const uint32_t groupCountY = 1, const uint32_t groupCountZ = 1);
inline bool drawMeshTasks(const hlsl::vector<uint16_t, 3> groupCount) {
return drawMeshTasks(groupCount.x, groupCount.y, groupCount.z);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather the hlsl::uint16_t3 be the primary signature, and the separate uint32 per dimension be the inline mapping to that

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can do a similar change to compute to match

Comment on lines -1205 to +1334
void CVulkanLogicalDevice::createGraphicsPipelines_impl(
IGPUPipelineCache* const pipelineCache,
const std::span<const IGPUGraphicsPipeline::SCreationParams> createInfos,
core::smart_refctd_ptr<IGPUGraphicsPipeline>* const output,
const SSpecializationValidationResult& validation
)
{
auto getVkStencilOpStateFrom = [](const asset::SStencilOpParams& params)->VkStencilOpState
{
return {
.failOp = static_cast<VkStencilOp>(params.failOp),
.passOp = static_cast<VkStencilOp>(params.passOp),
.depthFailOp = static_cast<VkStencilOp>(params.depthFailOp),
.compareOp = static_cast<VkCompareOp>(params.compareOp)
};
void PopulateViewport(VkPipelineViewportStateCreateInfo& outViewport, nbl::asset::SRasterizationParams const& raster) {
outViewport.viewportCount = raster.viewportCount;
// must be identical to viewport count unless VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT or VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT are used
outViewport.scissorCount = raster.viewportCount;
}


void PopulateRaster(VkPipelineRasterizationStateCreateInfo& outRaster, nbl::asset::SRasterizationParams const& raster) {
outRaster.depthClampEnable = raster.depthClampEnable;
outRaster.rasterizerDiscardEnable = raster.rasterizerDiscard;
outRaster.polygonMode = static_cast<VkPolygonMode>(raster.polygonMode);
outRaster.cullMode = static_cast<VkCullModeFlags>(raster.faceCullingMode);
outRaster.frontFace = raster.frontFaceIsCCW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE;
outRaster.depthBiasEnable = raster.depthBiasEnable;
}

void PopulateMultisample(VkPipelineMultisampleStateCreateInfo& outMultisample, nbl::asset::SRasterizationParams const& raster) {
outMultisample.rasterizationSamples = static_cast<VkSampleCountFlagBits>(0x1 << raster.samplesLog2);
if (raster.minSampleShadingUnorm > 0) {
outMultisample.sampleShadingEnable = true;
outMultisample.minSampleShading = float(raster.minSampleShadingUnorm) / 255.f;
}
else {
outMultisample.sampleShadingEnable = false;
outMultisample.minSampleShading = 0.f;
}
outMultisample.pSampleMask = raster.sampleMask;
outMultisample.alphaToCoverageEnable = raster.alphaToCoverageEnable;
outMultisample.alphaToOneEnable = raster.alphaToOneEnable;
}
VkStencilOpState getVkStencilOpStateFrom(const asset::SStencilOpParams& params) {
return {
.failOp = static_cast<VkStencilOp>(params.failOp),
.passOp = static_cast<VkStencilOp>(params.passOp),
.depthFailOp = static_cast<VkStencilOp>(params.depthFailOp),
.compareOp = static_cast<VkCompareOp>(params.compareOp)
};
}

const auto& features = getEnabledFeatures();
void PopulateDepthStencil(VkPipelineDepthStencilStateCreateInfo& outDepthStencil, nbl::asset::SRasterizationParams const& raster) {
outDepthStencil.depthTestEnable = raster.depthTestEnable();
outDepthStencil.depthWriteEnable = raster.depthWriteEnable;
outDepthStencil.depthCompareOp = static_cast<VkCompareOp>(raster.depthCompareOp);
outDepthStencil.depthBoundsTestEnable = raster.depthBoundsTestEnable;
outDepthStencil.stencilTestEnable = raster.stencilTestEnable();
outDepthStencil.front = getVkStencilOpStateFrom(raster.frontStencilOps);
outDepthStencil.back = getVkStencilOpStateFrom(raster.backStencilOps);
}

void PopulateColorBlend(
VkPipelineColorBlendStateCreateInfo& outColorBlend,
VkPipelineColorBlendAttachmentState*& outColorBlendAttachmentState,
nbl::asset::SBlendParams const& blend,
nbl::asset::IRenderpass::SCreationParams::SSubpassDescription const& subpass
) {
//outColorBlend->flags no attachment order access yet
outColorBlend.logicOpEnable = blend.logicOp != asset::ELO_NO_OP;
outColorBlend.logicOp = getVkLogicOpFromLogicOp(blend.logicOp);
outColorBlend.pAttachments = outColorBlendAttachmentState;
for (auto i = 0; i < IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments; i++) {
if (subpass.colorAttachments[i].render.used()) {
const auto& params = blend.blendParams[i];
outColorBlendAttachmentState->blendEnable = params.blendEnabled();
outColorBlendAttachmentState->srcColorBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.srcColorFactor));
outColorBlendAttachmentState->dstColorBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.dstColorFactor));
outColorBlendAttachmentState->colorBlendOp = getVkBlendOpFromBlendOp(static_cast<asset::E_BLEND_OP>(params.colorBlendOp));
outColorBlendAttachmentState->srcAlphaBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.srcAlphaFactor));
outColorBlendAttachmentState->dstAlphaBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.dstAlphaFactor));
outColorBlendAttachmentState->alphaBlendOp = getVkBlendOpFromBlendOp(static_cast<asset::E_BLEND_OP>(params.alphaBlendOp));
outColorBlendAttachmentState->colorWriteMask = getVkColorComponentFlagsFromColorWriteMask(params.colorWriteMask);
outColorBlendAttachmentState++;
//^that pointer iterator is how we ensure the attachments or consecutive
}
}
outColorBlend.attachmentCount = std::distance<const VkPipelineColorBlendAttachmentState*>(outColorBlend.pAttachments, outColorBlendAttachmentState);
}

template<typename SCreationParams>
void PopulateMeshGraphicsCommonData(
const std::span<const SCreationParams> createInfos,
core::vector<VkGraphicsPipelineCreateInfo>& vk_createInfos,

core::vector<VkPipelineViewportStateCreateInfo>& vk_viewportStates,
core::vector<VkPipelineRasterizationStateCreateInfo>& vk_rasterizationStates,
core::vector<VkPipelineMultisampleStateCreateInfo>& vk_multisampleStates,
core::vector<VkPipelineDepthStencilStateCreateInfo>& vk_depthStencilStates,
core::vector<VkPipelineColorBlendStateCreateInfo>& vk_colorBlendStates,
core::vector<VkPipelineColorBlendAttachmentState>& vk_colorBlendAttachmentStates,

core::vector<VkDynamicState>& vk_dynamicStates,
const VkPipelineDynamicStateCreateInfo& vk_dynamicStateCreateInfo
) {
//the main concern is lifetime, so don't want to construct, move, or copy anything in here

auto outColorBlendAttachmentState = vk_colorBlendAttachmentStates.data(); //the pointer iterator is used

core::vector<VkDynamicState> vk_dynamicStates = {

for (uint32_t i = 0; i < createInfos.size(); i++) { //whats the maximum number of pipelines that can be created at once? uint32_t to be safe
auto& info = createInfos[i];
const auto& blend = info.cached.blend;
const auto& raster = info.cached.rasterization;
const auto& subpass = info.renderpass->getCreationParameters().subpasses[info.cached.subpassIx];

initPipelineCreateInfo(&vk_createInfos[i], info);

PopulateViewport(vk_viewportStates[i], raster);
PopulateRaster(vk_rasterizationStates[i], raster);
PopulateMultisample(vk_multisampleStates[i], raster);
PopulateDepthStencil(vk_depthStencilStates[i], raster);
PopulateColorBlend(vk_colorBlendStates[i], outColorBlendAttachmentState, blend, subpass);
//PopulateDynamicState(dynState, ?)


vk_createInfos[i].pViewportState = &vk_viewportStates[i];
vk_createInfos[i].pRasterizationState = &vk_rasterizationStates[i];
vk_createInfos[i].pMultisampleState = &vk_multisampleStates[i];
vk_createInfos[i].pDepthStencilState = &vk_depthStencilStates[i];
vk_createInfos[i].pColorBlendState = &vk_colorBlendStates[i];
vk_createInfos[i].pDynamicState = &vk_dynamicStateCreateInfo;
vk_createInfos[i].renderPass = static_cast<const CVulkanRenderpass*>(info.renderpass)->getInternalObject();
vk_createInfos[i].subpass = info.cached.subpassIx;
//handle
//index
//layout?
// ^ handled in initPipelineCreateInfo
}
}

core::vector<VkDynamicState> getDefaultDynamicStates(SPhysicalDeviceFeatures const& features) {
core::vector<VkDynamicState> ret = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevyuu you review this and give it the okay

Copy link
Member

@devshgraphicsprogramming devshgraphicsprogramming Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually wait a ssecond, @GDBobby I think you could turn all these free floating functions into struct methods of a struct that has reference members like core::vector<>& or span members const std::span<> since the vectors are preallocated

Comment on lines +1352 to +1359
//maximum cleanliness,i tried it and im not a big fan
//struct CommonPipelineStruct {
// VkPipelineRasterizationStateCreateInfo vk_rasterizationStates{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,nullptr,0 };
// VkPipelineMultisampleStateCreateInfo vk_multisampleStates{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,nullptr,0 };
// VkPipelineDepthStencilStateCreateInfo vk_depthStencilStates{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,nullptr,0 };
// VkPipelineColorBlendStateCreateInfo vk_colorBlendStates{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,nullptr,0 };
// core::vector<VkPipelineColorBlendAttachmentState> vk_colorBlendAttachmentStates{ IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments };
//};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

me neither because this messes with our SVO later on

Comment on lines +1287 to +1295
core::vector<VkPipelineViewportStateCreateInfo>& vk_viewportStates,
core::vector<VkPipelineRasterizationStateCreateInfo>& vk_rasterizationStates,
core::vector<VkPipelineMultisampleStateCreateInfo>& vk_multisampleStates,
core::vector<VkPipelineDepthStencilStateCreateInfo>& vk_depthStencilStates,
core::vector<VkPipelineColorBlendStateCreateInfo>& vk_colorBlendStates,
core::vector<VkPipelineColorBlendAttachmentState>& vk_colorBlendAttachmentStates,

core::vector<VkDynamicState>& vk_dynamicStates,
const VkPipelineDynamicStateCreateInfo& vk_dynamicStateCreateInfo

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can create a struct with reference members though to pack this all up

Comment on lines +1412 to +1417
//not used in mesh pipelines
for (auto& outCreateInfo : vk_createInfos) {
outCreateInfo.pVertexInputState = nullptr;
outCreateInfo.pInputAssemblyState = nullptr;
outCreateInfo.pTessellationState = nullptr;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because we give a default value to the vector constructor of vk_createInfos, these should be nullptr initialized already unless you write to them with your utility functions

Comment on lines +1511 to +1520
//maximum cleanliness, I create a struct that holds this for mesh and graphics?
core::vector<VkGraphicsPipelineCreateInfo> vk_createInfos(createInfos.size(), { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,nullptr });

core::vector<VkPipelineRasterizationStateCreateInfo> vk_rasterizationStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,nullptr,0 });
core::vector<VkPipelineMultisampleStateCreateInfo> vk_multisampleStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,nullptr,0 });
core::vector<VkPipelineDepthStencilStateCreateInfo> vk_depthStencilStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,nullptr,0 });
core::vector<VkPipelineColorBlendStateCreateInfo> vk_colorBlendStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,nullptr,0 });
core::vector<VkPipelineColorBlendAttachmentState> vk_colorBlendAttachmentStates(createInfos.size() * IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments);

core::vector<VkDynamicState> vk_dynamicStates = getDefaultDynamicStates(features);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can but keep it separate from the util struct that works on spans

Comment on lines -1255 to +1660
core::vector<VkGraphicsPipelineCreateInfo> vk_createInfos(createInfos.size(),{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,nullptr});

const auto maxShaderStages = createInfos.size()*IGPUGraphicsPipeline::GRAPHICS_SHADER_STAGE_COUNT;
core::vector<VkPipelineShaderStageCreateInfo> vk_shaderStage(maxShaderStages,{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,nullptr});
core::vector<VkShaderModuleCreateInfo> vk_shaderModule(maxShaderStages,{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,nullptr, 0});
core::vector<std::string> entryPoints(maxShaderStages);
core::vector<VkPipelineShaderStageRequiredSubgroupSizeCreateInfo> vk_requiredSubgroupSize(maxShaderStages,{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO,nullptr
});
core::vector<VkSpecializationInfo> vk_specializationInfos(maxShaderStages,{0,nullptr,0,nullptr});
core::vector<VkSpecializationMapEntry> vk_specializationMapEntry(validation.count);
core::vector<uint8_t> specializationData(validation.dataSize);
core::vector<VkPipelineVertexInputStateCreateInfo> vk_vertexInput(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,nullptr,0});
core::vector<VkVertexInputBindingDescription> vk_inputBinding(createInfos.size()*asset::SVertexInputParams::MAX_ATTR_BUF_BINDING_COUNT);
core::vector<VkVertexInputAttributeDescription> vk_inputAttribute(createInfos.size()*asset::SVertexInputParams::MAX_VERTEX_ATTRIB_COUNT);
core::vector<VkPipelineInputAssemblyStateCreateInfo> vk_inputAssembly(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,nullptr,0});
core::vector<VkPipelineTessellationStateCreateInfo> vk_tessellation(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,nullptr,0});
core::vector<VkPipelineViewportStateCreateInfo> vk_viewportStates(createInfos.size(),{
//maximum cleanliness, I create a struct that holds this for mesh and graphics?
core::vector<VkGraphicsPipelineCreateInfo> vk_createInfos(createInfos.size(), { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,nullptr });

core::vector<VkPipelineRasterizationStateCreateInfo> vk_rasterizationStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,nullptr,0 });
core::vector<VkPipelineMultisampleStateCreateInfo> vk_multisampleStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,nullptr,0 });
core::vector<VkPipelineDepthStencilStateCreateInfo> vk_depthStencilStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,nullptr,0 });
core::vector<VkPipelineColorBlendStateCreateInfo> vk_colorBlendStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,nullptr,0 });
core::vector<VkPipelineColorBlendAttachmentState> vk_colorBlendAttachmentStates(createInfos.size() * IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments);

core::vector<VkDynamicState> vk_dynamicStates = getDefaultDynamicStates(features);

const VkPipelineDynamicStateCreateInfo vk_dynamicStateCreateInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0u,
.dynamicStateCount = static_cast<uint32_t>(vk_dynamicStates.size()),
.pDynamicStates = vk_dynamicStates.data()
};
core::vector<VkPipelineViewportStateCreateInfo> vk_viewportStates(createInfos.size(), {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.pNext = nullptr, // the extensions that interest us have a dynamic state variant anyway
.flags = 0, // must be 0
.viewportCount = 0,
.pViewports = nullptr,
.scissorCount = 0,
.pScissors = nullptr,
});
core::vector<VkPipelineRasterizationStateCreateInfo> vk_rasterizationStates(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,nullptr,0});
core::vector<VkPipelineMultisampleStateCreateInfo> vk_multisampleStates(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,nullptr,0});
core::vector<VkPipelineDepthStencilStateCreateInfo> vk_depthStencilStates(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,nullptr,0});
core::vector<VkPipelineColorBlendStateCreateInfo> vk_colorBlendStates(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,nullptr,0});
core::vector<VkPipelineColorBlendAttachmentState> vk_colorBlendAttachmentStates(createInfos.size()*IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments);
});

PopulateMeshGraphicsCommonData(
createInfos, vk_createInfos,

vk_viewportStates,
vk_rasterizationStates,
vk_multisampleStates,
vk_depthStencilStates,
vk_colorBlendStates,
vk_colorBlendAttachmentStates,

vk_dynamicStates, vk_dynamicStateCreateInfo
);


core::vector<VkVertexInputBindingDescription> vk_inputBinding(createInfos.size() * asset::SVertexInputParams::MAX_ATTR_BUF_BINDING_COUNT);
core::vector<VkVertexInputAttributeDescription> vk_inputAttribute(createInfos.size() * asset::SVertexInputParams::MAX_VERTEX_ATTRIB_COUNT);
core::vector<VkPipelineInputAssemblyStateCreateInfo> vk_inputAssembly(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,nullptr,0 });
core::vector<VkPipelineTessellationStateCreateInfo> vk_tessellation(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,nullptr,0 });
core::vector<VkPipelineVertexInputStateCreateInfo> vk_vertexInput(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,nullptr,0 });

auto outCreateInfo = vk_createInfos.data();
auto outShaderStage = vk_shaderStage.data();
auto outEntryPoints = entryPoints.data();
auto outShaderModule = vk_shaderModule.data();
auto outRequiredSubgroupSize = vk_requiredSubgroupSize.data();
auto outSpecInfo = vk_specializationInfos.data();
auto outSpecMapEntry = vk_specializationMapEntry.data();
auto outSpecData = specializationData.data();
auto outVertexInput = vk_vertexInput.data();
auto outInputBinding = vk_inputBinding.data();
auto outInputAttribute = vk_inputAttribute.data();
auto outInputAssembly = vk_inputAssembly.data();
auto outTessellation = vk_tessellation.data();
auto outViewport = vk_viewportStates.data();
auto outRaster = vk_rasterizationStates.data();
auto outMultisample = vk_multisampleStates.data();
auto outDepthStencil = vk_depthStencilStates.data();
auto outColorBlend = vk_colorBlendStates.data();
auto outColorBlendAttachmentState = vk_colorBlendAttachmentStates.data();
auto outInputAssembly = vk_inputAssembly.data();

//ill acknowledge this additional looping is a little ugly
//input and tess
for (const auto& info : createInfos)
{
initPipelineCreateInfo(outCreateInfo,info);
outCreateInfo->pStages = outShaderStage;
auto processSpecShader = [&](IGPUPipelineBase::SShaderSpecInfo spec, hlsl::ShaderStage shaderStage)
{
if (spec.shader)
{
*(outShaderStage++) = getVkShaderStageCreateInfoFrom(spec, shaderStage, false, outShaderModule, outEntryPoints, outRequiredSubgroupSize, outSpecInfo, outSpecMapEntry, outSpecData);
outCreateInfo->stageCount = std::distance<decltype(outCreateInfo->pStages)>(outCreateInfo->pStages, outShaderStage);
}
};
processSpecShader(info.vertexShader, hlsl::ShaderStage::ESS_VERTEX);
processSpecShader(info.tesselationControlShader, hlsl::ShaderStage::ESS_TESSELLATION_CONTROL);
processSpecShader(info.tesselationEvaluationShader, hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION);
processSpecShader(info.geometryShader, hlsl::ShaderStage::ESS_GEOMETRY);
processSpecShader(info.fragmentShader, hlsl::ShaderStage::ESS_FRAGMENT);

// when dealing with mesh shaders, the vertex input and assembly state will be null
{
{
const auto& vertexInputParams = info.cached.vertexInput;
outVertexInput->pVertexBindingDescriptions = outInputBinding;
for (auto b=0u; b<asset::SVertexInputParams::MAX_ATTR_BUF_BINDING_COUNT; b++)
if (vertexInputParams.enabledBindingFlags&(1<<b))
const auto& vertexInputParams = info.cached.vertexInput;
outVertexInput->pVertexBindingDescriptions = outInputBinding;
for (auto b = 0u; b < asset::SVertexInputParams::MAX_ATTR_BUF_BINDING_COUNT; b++)
if (vertexInputParams.enabledBindingFlags & (1 << b))
{
outInputBinding->binding = b;
outInputBinding->stride = vertexInputParams.bindings[b].stride;
outInputBinding->inputRate = static_cast<VkVertexInputRate>(vertexInputParams.bindings[b].inputRate);
outInputBinding++;
}
outVertexInput->vertexBindingDescriptionCount = std::distance<const VkVertexInputBindingDescription*>(outVertexInput->pVertexBindingDescriptions,outInputBinding);
outVertexInput->pVertexAttributeDescriptions = outInputAttribute;
for (auto l=0u; l<asset::SVertexInputParams::MAX_VERTEX_ATTRIB_COUNT; l++)
if (vertexInputParams.enabledAttribFlags&(1<<l))
outVertexInput->vertexBindingDescriptionCount = std::distance<const VkVertexInputBindingDescription*>(outVertexInput->pVertexBindingDescriptions, outInputBinding);
outVertexInput->pVertexAttributeDescriptions = outInputAttribute;
for (auto l = 0u; l < asset::SVertexInputParams::MAX_VERTEX_ATTRIB_COUNT; l++)
if (vertexInputParams.enabledAttribFlags & (1 << l))
{
outInputAttribute->location = l;
outInputAttribute->binding = vertexInputParams.attributes[l].binding;
outInputAttribute->format = getVkFormatFromFormat(static_cast<asset::E_FORMAT>(vertexInputParams.attributes[l].format));
outInputAttribute->offset = vertexInputParams.attributes[l].relativeOffset;
outInputAttribute++;
}
outVertexInput->vertexAttributeDescriptionCount = std::distance<const VkVertexInputAttributeDescription*>(outVertexInput->pVertexAttributeDescriptions,outInputAttribute);
}
outCreateInfo->pVertexInputState = outVertexInput++;
{
const auto& primAssParams = info.cached.primitiveAssembly;
outInputAssembly->topology = static_cast<VkPrimitiveTopology>(primAssParams.primitiveType);
outInputAssembly->primitiveRestartEnable = primAssParams.primitiveRestartEnable;
}
outCreateInfo->pInputAssemblyState = outInputAssembly++;
outVertexInput->vertexAttributeDescriptionCount = std::distance<const VkVertexInputAttributeDescription*>(outVertexInput->pVertexAttributeDescriptions, outInputAttribute);
}
outCreateInfo->pVertexInputState = outVertexInput++;
{
const auto& primAssParams = info.cached.primitiveAssembly;
outInputAssembly->topology = static_cast<VkPrimitiveTopology>(primAssParams.primitiveType);
outInputAssembly->primitiveRestartEnable = primAssParams.primitiveRestartEnable;
}
outCreateInfo->pInputAssemblyState = outInputAssembly++;

if (info.tesselationControlShader.shader || info.tesselationEvaluationShader.shader)
{
outTessellation->patchControlPoints = info.cached.primitiveAssembly.tessPatchVertCount;
outCreateInfo->pTessellationState = outTessellation++;
}

const auto& raster = info.cached.rasterization;
{
outViewport->viewportCount = raster.viewportCount;
// must be identical to viewport count unless VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT or VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT are used
outViewport->scissorCount = raster.viewportCount;
outCreateInfo->pViewportState = outViewport++;
}
{
outRaster->depthClampEnable = raster.depthClampEnable;
outRaster->rasterizerDiscardEnable = raster.rasterizerDiscard;
outRaster->polygonMode = static_cast<VkPolygonMode>(raster.polygonMode);
outRaster->cullMode = static_cast<VkCullModeFlags>(raster.faceCullingMode);
outRaster->frontFace = raster.frontFaceIsCCW ? VK_FRONT_FACE_COUNTER_CLOCKWISE:VK_FRONT_FACE_CLOCKWISE;
outRaster->depthBiasEnable = raster.depthBiasEnable;
outCreateInfo->pRasterizationState = outRaster++;
}
{
outMultisample->rasterizationSamples = static_cast<VkSampleCountFlagBits>(0x1<<raster.samplesLog2);
if (raster.minSampleShadingUnorm>0)
{
outMultisample->sampleShadingEnable = true;
outMultisample->minSampleShading = float(raster.minSampleShadingUnorm)/255.f;
}
else
{
outMultisample->sampleShadingEnable = false;
outMultisample->minSampleShading = 0.f;
}
outMultisample->pSampleMask = raster.sampleMask;
outMultisample->alphaToCoverageEnable = raster.alphaToCoverageEnable;
outMultisample->alphaToOneEnable = raster.alphaToOneEnable;
outCreateInfo->pMultisampleState = outMultisample++;
}
{
//outDepthStencil->flags no attachment order access yet
outDepthStencil->depthTestEnable = raster.depthTestEnable();
outDepthStencil->depthWriteEnable = raster.depthWriteEnable;
outDepthStencil->depthCompareOp = static_cast<VkCompareOp>(raster.depthCompareOp);
outDepthStencil->depthBoundsTestEnable = raster.depthBoundsTestEnable;
outDepthStencil->stencilTestEnable = raster.stencilTestEnable();
outDepthStencil->front = getVkStencilOpStateFrom(raster.frontStencilOps);
outDepthStencil->back = getVkStencilOpStateFrom(raster.backStencilOps);
outCreateInfo->pDepthStencilState = outDepthStencil++;
}
{
const auto& blend = info.cached.blend;
const auto& subpass = info.renderpass->getCreationParameters().subpasses[info.cached.subpassIx];
//outColorBlend->flags no attachment order access yet
outColorBlend->logicOpEnable = blend.logicOp!=asset::ELO_NO_OP;
outColorBlend->logicOp = getVkLogicOpFromLogicOp(blend.logicOp);
outColorBlend->pAttachments = outColorBlendAttachmentState;
for (auto i=0; i<IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments; i++)
if (subpass.colorAttachments[i].render.used())
outCreateInfo++;
}

const auto maxShaderStages = createInfos.size() * IGPUGraphicsPipeline::GRAPHICS_SHADER_STAGE_COUNT;
core::vector<VkPipelineShaderStageCreateInfo> vk_shaderStage(maxShaderStages, { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,nullptr });
core::vector<VkShaderModuleCreateInfo> vk_shaderModule(maxShaderStages, { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,nullptr, 0 });
core::vector<std::string> entryPoints(maxShaderStages);
core::vector<VkPipelineShaderStageRequiredSubgroupSizeCreateInfo> vk_requiredSubgroupSize(maxShaderStages, {
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO,nullptr
});
core::vector<VkSpecializationInfo> vk_specializationInfos(maxShaderStages, { 0,nullptr,0,nullptr });
core::vector<VkSpecializationMapEntry> vk_specializationMapEntry(validation.count);
core::vector<uint8_t> specializationData(validation.dataSize);

outCreateInfo = vk_createInfos.data();
auto outShaderStage = vk_shaderStage.data();
auto outEntryPoints = entryPoints.data();
auto outShaderModule = vk_shaderModule.data();
auto outRequiredSubgroupSize = vk_requiredSubgroupSize.data();
auto outSpecInfo = vk_specializationInfos.data();
auto outSpecMapEntry = vk_specializationMapEntry.data();
auto outSpecData = specializationData.data();

//shader
for (const auto& info : createInfos)
{
outCreateInfo->pStages = outShaderStage;
auto processSpecShader = [&](IGPUPipelineBase::SShaderSpecInfo spec, hlsl::ShaderStage shaderStage)
{
const auto& params = blend.blendParams[i];
outColorBlendAttachmentState->blendEnable = params.blendEnabled();
outColorBlendAttachmentState->srcColorBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.srcColorFactor));
outColorBlendAttachmentState->dstColorBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.dstColorFactor));
outColorBlendAttachmentState->colorBlendOp = getVkBlendOpFromBlendOp(static_cast<asset::E_BLEND_OP>(params.colorBlendOp));
outColorBlendAttachmentState->srcAlphaBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.srcAlphaFactor));
outColorBlendAttachmentState->dstAlphaBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.dstAlphaFactor));
outColorBlendAttachmentState->alphaBlendOp = getVkBlendOpFromBlendOp(static_cast<asset::E_BLEND_OP>(params.alphaBlendOp));
outColorBlendAttachmentState->colorWriteMask = getVkColorComponentFlagsFromColorWriteMask(params.colorWriteMask);
outColorBlendAttachmentState++;
}
outColorBlend->attachmentCount = std::distance<const VkPipelineColorBlendAttachmentState*>(outColorBlend->pAttachments,outColorBlendAttachmentState);
outCreateInfo->pColorBlendState = outColorBlend++;
}
outCreateInfo->pDynamicState = &vk_dynamicStateCreateInfo;
outCreateInfo->renderPass = static_cast<const CVulkanRenderpass*>(info.renderpass)->getInternalObject();
outCreateInfo->subpass = info.cached.subpassIx;
if (spec.shader)
{
*(outShaderStage++) = getVkShaderStageCreateInfoFrom(spec,
shaderStage,
false,
outShaderModule,
outEntryPoints,
outRequiredSubgroupSize,
outSpecInfo,
outSpecMapEntry,
outSpecData
);
outCreateInfo->stageCount = std::distance<decltype(outCreateInfo->pStages)>(outCreateInfo->pStages, outShaderStage);
}
};
processSpecShader(info.vertexShader, hlsl::ShaderStage::ESS_VERTEX);
processSpecShader(info.tesselationControlShader, hlsl::ShaderStage::ESS_TESSELLATION_CONTROL);
processSpecShader(info.tesselationEvaluationShader, hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION);
processSpecShader(info.geometryShader, hlsl::ShaderStage::ESS_GEOMETRY);
processSpecShader(info.fragmentShader, hlsl::ShaderStage::ESS_FRAGMENT);

outCreateInfo++;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevyuu review this

Comment on lines +6 to +9
{

CVulkanMeshPipeline::~CVulkanMeshPipeline()
{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont do extra indents in namespaces

Comment on lines +12 to +14
//potentially collapse this so Mesh just uses CVulkanGraphicsPipeline
//if thats done, BindMesh can go away
class CVulkanMeshPipeline final : public IGPUMeshPipeline

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you still need correct inheritance unfortunately, you could template the class though

template<typename Base> requires std::is_base_of_v<IGPURasterizationPipeline,Base>
class CVulkanRasterizationPipeline : public Base

Comment on lines +1873 to +1875
meshShaderFeatures.primitiveFragmentShadingRateMeshShader = VK_FALSE;//needs to be explicitly set?
meshShaderFeatures.meshShaderQueries = VK_FALSE;
meshShaderFeatures.multiviewMeshShader = VK_FALSE;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the question is, for regular Multiview, queries and Shading rate, do we currently have them as limits or features?

Comment on lines +826 to +863
//check if features are existant first
//potentially put a copy of VkPhysicalDeviceMeshShaderFeaturesEXT directly into features
//depends on the less obvious properties
if (isExtensionSupported(VK_EXT_MESH_SHADER_EXTENSION_NAME)) {
features.meshShader = meshShaderFeatures.meshShader;
features.taskShader = meshShaderFeatures.taskShader;
//TODO
//VkBool32 multiviewMeshShader;
//VkBool32 primitiveFragmentShadingRateMeshShader;
//VkBool32 meshShaderQueries;

//VkPhysicalDeviceMeshShaderPropertiesEXT
//#define LIMIT_INIT_MESH(limitMemberName) properties.limits.limitMemberName = meshShaderProperties.limitMemberName
//LIMIT_INIT_MESH(maxTaskWorkGroupTotalCount);
//LIMIT_INIT_MESH(maxTaskWorkGroupInvocations);
//LIMIT_INIT_MESH(maxTaskPayloadSize);
//LIMIT_INIT_MESH(maxTaskSharedMemorySize);
//LIMIT_INIT_MESH(maxTaskPayloadAndSharedMemorySize);
//LIMIT_INIT_MESH(maxMeshWorkGroupInvocations);
//LIMIT_INIT_MESH(maxMeshSharedMemorySize);
//LIMIT_INIT_MESH(maxMeshPayloadAndSharedMemorySize);
//LIMIT_INIT_MESH(maxMeshOutputMemorySize);
//LIMIT_INIT_MESH(maxMeshOutputComponents);
//LIMIT_INIT_MESH(maxMeshOutputVertices);
//LIMIT_INIT_MESH(maxMeshOutputPrimitives);
//LIMIT_INIT_MESH(maxMeshOutputLayers);
//LIMIT_INIT_MESH(maxMeshMultiviewViewCount);
//LIMIT_INIT_MESH(maxMeshOutputPerVertexGranularity);
//LIMIT_INIT_MESH(maxMeshOutputPerPrimitiveGranularity);

//for(uint8_t i = 0; i < 3; i++){
// LIMIT_INIT_MESH(maxTaskWorkGroupCount[i]);
// LIMIT_INIT_MESH(maxTaskWorkGroupSize[i]);
// LIMIT_INIT_MESH(maxMeshWorkGroupCount[i]);
// LIMIT_INIT_MESH(maxMeshWorkGroupSize[i]);
//}
//#undef LIMIT_INIT_MESH
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Erfan-Ahmadi review and advise on how to expose

return drawMeshTasks_impl(groupCountX, groupCountY, groupCountZ);
}

bool IGPUCommandBuffer::drawMeshTasksIndirect(const asset::SBufferBinding<const IGPUBuffer>& binding, const uint32_t drawCount, uint32_t stride)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw is there a flavour of task shaders where count comes from a buffer, like Multi Draw Indirect ?

}
if (invalidBufferRange({ binding.offset,stride * (drawCount - 1u) + sizeof(hlsl::DrawMeshTasksIndirectCommand_t),binding.buffer }, alignof(uint32_t), IGPUBuffer::EUF_INDIRECT_BUFFER_BIT))
return false;
} // i get the feeling the vk command shouldnt be called if drawCount is 0, but this is how drawindirect does it

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check the spec and decide

Comment on lines +50 to +53
inline std::span<SShaderSpecInfo> getSpecInfos(const hlsl::ShaderStage stage)
{
return base_t::getSpecInfos(stage);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can't hand out mutable spans without checking immutability first

Comment on lines +55 to +72
SShaderSpecInfo* getSpecInfo(const hlsl::ShaderStage stage)
{
if (!isMutable()) return nullptr;
switch (stage) {
case hlsl::ShaderStage::ESS_TASK: return &m_specInfos[0];
case hlsl::ShaderStage::ESS_MESH: return &m_specInfos[1];
case hlsl::ShaderStage::ESS_FRAGMENT: return &m_specInfos[2];
}
return nullptr;
}

const SShaderSpecInfo* getSpecInfo(const hlsl::ShaderStage stage) const
{
const auto stageIndex = stageToIndex(stage);
if (stageIndex != -1)
return &m_specInfos[stageIndex];
return nullptr;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we have duplicate code, the single pointer return value signatures should go in ICPURasterizationPipeline (these are pipelines which can only have one shader per stage

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also should probably be done in terms of span<> getSpecInfo(stage)

Comment on lines +29 to +38
inline const SCachedCreationParams& getCachedCreationParams() const
{
return pipeline_base_t::getCachedCreationParams();
}

inline SCachedCreationParams& getCachedCreationParams()
{
assert(isMutable());
return m_params;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the creation params are identical for Gfx and MEsh, should go in ICPURasterizationPipeline

namespace nbl::asset
{

class ICPUMeshPipeline final : public ICPUPipeline<IMeshPipeline<ICPUPipelineLayout,ICPURenderpass>>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make a ICPURasterizationPipeline : IRasterizationPipeline<ICPUPipelineLayout,ICPUrenderpass>

Comment on lines +51 to +55
namespace nbl::video
{

class IGPUMeshPipeline : public IGPUPipeline<asset::IMeshPipeline<const IGPUPipelineLayout, const IGPURenderpass>>
{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no extra indents for a namespace

Comment on lines +836 to +842
bool MeshGraphicsCommonValidation(
const IGPURenderpass* renderpass, uint8_t subpassIndex,
SPhysicalDeviceLimits const& limits, SPhysicalDeviceFeatures const& features,
nbl::asset::SRasterizationParams const& rasterParams, nbl::asset::SBlendParams const& blendParams,
const system::logger_opt_ptr m_logger,
const IPhysicalDevice::SFormatImageUsages& formatUsages
) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it a method of ILogicalDevice so you don't have to pass features, limits, logger and format usages around

Comment on lines +952 to +953
if (!features.taskShader) {
NBL_LOG_ERROR("Feature `mesh shader` is not enabled");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo?

Comment on lines 864 to 878
return false;
}

if (ci.geometryShader.shader)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes you've found a typo, well done!

Comment on lines +958 to +960
//check extensions here
//it SEEMS like createGraphicsPipeline does, but it does it in a weird way I don't understand?
//geo and tess are just flat disabled??

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its because we never used them, typo galore, you can fix

Comment on lines 1038 to 1048
if (ci.tesselationEvaluationShader.shader)
{
NBL_LOG_ERROR("Cannot create IGPUShader for %p, Tessellation Shader feature not enabled!", ci.tesselationEvaluationShader.shader);
return false;
}

if (ci.geometryShader.shader)
{
NBL_LOG_ERROR("Cannot create IGPUShader for %p, Geometry Shader feature not enabled!", ci.geometryShader.shader);
return false;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep its a bug

Comment on lines 1050 to 1055
auto renderpass = ci.renderpass;
if (!renderpass->wasCreatedBy(this))
{
NBL_LOG_ERROR("Invalid renderpass was given (params[%u])", ix);
return false;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be commonalized in MeshGraphicsCommonValidation I think

Comment on lines +15 to +16
https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-PrimitiveId-06264
** If the pipeline requires pre-rasterization shader state, it includes a mesh shader and the fragment shader code reads from an input variable that is decorated with PrimitiveId, then the mesh shader code must write to a matching output variable, decorated with PrimitiveId, in all execution paths

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this you can't validate cheaply without parsing SPIR-V, also its an "all execution paths" thing so its a runtime thing to be checked with GPU AV layer

Comment on lines +18 to +19
https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-renderPass-07064
* If renderPass is not VK_NULL_HANDLE, the pipeline is being created with pre-rasterization shader state, subpass viewMask is not 0, and multiviewMeshShader is not enabled, then pStages must not include a mesh shader

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can check that

Comment on lines +21 to +24
https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-None-02322
* If the pipeline requires pre-rasterization shader state, and there are any mesh shader stages in the pipeline there must not be any shader stage in the pipeline with a Xfb execution mode
*** whats a xfb

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transform feedback, a nasty OpenGL carryover extension we don't use

Comment on lines +25 to +29
https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-shaderMeshEnqueue-10187
* If the shaderMeshEnqueue feature is not enabled, shaders specified by pStages must not declare the ShaderEnqueueAMDX capability
https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-flags-10188
* If flags does not include VK_PIPELINE_CREATE_LIBRARY_BIT_KHR, shaders specified by pStages must not declare the ShaderEnqueueAMDX capability
*** my understanding is nabla strictly controls it's extensions, so this shouldnt be an issue

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

year we're not going into AMDX or NVX extensions, also no pipeline libs yet

https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07066
* If the pipeline requires pre-rasterization shader state, and includes a mesh shader, there must be no element of the
* pDynamicStates member of pDynamicState set to VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE, or VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we choose the dynamic state ourselves (opinionated pick), and I think we never made those two dynamic, ever

maybe check the PRIMITIVE_RESTART enable

Comment on lines +43 to +46
https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-renderPass-07720
* If renderPass is VK_NULL_HANDLE, the pipeline is being created with pre-rasterization shader state, and
* VkPipelineRenderingCreateInfo::viewMask is not 0, and multiviewMeshShader is not enabled, then pStages must not include a mesh shader

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what its saying is that you can't use multivew in pipeline create info with a mesh shader if you don't have the multiviewMeshShader feature

Basically there's the old multivew feature, but that only controls if multiview is available for a graphics pipeline, for mesh you have another thing to check instead

namespace nbl::video
{

class IGPUMeshPipeline : public IGPUPipeline<asset::IMeshPipeline<const IGPUPipelineLayout, const IGPURenderpass>>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems you have not commited the file with IMeshPipeline !

Comment on lines +103 to +109
static inline int8_t stageToIndex(const hlsl::ShaderStage stage)
{
const auto stageIx = hlsl::findLSB(stage);
if (stageIx < 0 || stageIx >= MESH_SHADER_STAGE_COUNT || hlsl::bitCount(stage)!=1)
return -1;
return stageIx;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fairly certain this is wrong, and you need to return stageIx-offset since only in gfx pipeline VERTEX is 0th bit

if (!processSpecInfo(fragmentShader, hlsl::ShaderStage::ESS_FRAGMENT)) return {};

if (!hasRequiredStages(stagePresence))
return {};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because you haven't committed the IMeshPipeline.h file I can't see the impl of this

if (!hasRequiredStages(stagePresence))
return {};

//if (!vertexShader.shader) return {}; //i dont quite understand why this line was in IGPUGraphics. checking if the shader itself was made correctly?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its because graphics pipeline MUST have a vertex shader, much like how a Mesh pipeline must have a mesh shader

Fragment and Task are optional for mesh pipe


inline uint32_t getShaderCount() const
{
uint32_t count = 0; //count = 2 and only check task shader??

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no what you have now is correct

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants